package com.earthea.application.system.domain.service.impl;

import com.earthea.application.common.constant.ConfigConstants;
import com.earthea.application.common.entity.TableDataInfo;
import com.earthea.application.common.enums.CacheEnum;
import com.earthea.application.system.domain.entity.SysConfig;
import com.earthea.application.system.domain.service.ISysConfigService;
import com.earthea.application.system.entity.request.SysConfigReq;
import com.earthea.application.system.mapper.SysConfigMapper;
import com.earthea.cache.CacheService;
import com.google.common.base.Preconditions;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 系统配置实现
 */
@Service
public class SysConfigServiceImpl implements ISysConfigService {

    @Autowired(required = false)
    private CacheService cacheService;

    private static final SysConfig DEFAULT_SELECT_CONFIG = new SysConfig();

    @Autowired
    private SysConfigMapper sysConfigMapper;

    /**
     * 项目启动时，初始化参数到缓存
     */
    @PostConstruct
    public void init() {
        loadingConfigCache();
    }

    @Override
    public int insert(SysConfig config) {
        Preconditions.checkNotNull(config, "config must be not null");
        int count = sysConfigMapper.insert(config);
        if (count > 0 && enableCache()) {
            cacheService.setex(getCacheKey(config.getConfigKey()), config.getConfigValue(), ConfigConstants.SYS_CONFIG_TIMEOUT);
        }
        return count;
    }

    @Override
    public int update(SysConfig config) {
        Preconditions.checkNotNull(config, "config must be not null");
        int count = sysConfigMapper.update(config);
        if (count > 0 && enableCache()) {
            cacheService.setex(getCacheKey(config.getConfigKey()), config.getConfigValue(), ConfigConstants.SYS_CONFIG_TIMEOUT);
        }
        return count;
    }

    @Override
    public boolean checkConfigKeyUnique(String key) {
        SysConfig info = getConfig(key);
        return Objects.isNull(info);
    }

    @Override
    public SysConfig getConfig(Object idOrKey) {
        Preconditions.checkArgument(Objects.nonNull(idOrKey), "idOrKey must be not null");
        if (idOrKey instanceof String) {
            DEFAULT_SELECT_CONFIG.setConfigKey((String) idOrKey);
        } else if (idOrKey instanceof Long) {
            DEFAULT_SELECT_CONFIG.setConfigId((Long) idOrKey);
        } else {
            return null;
        }
        return sysConfigMapper.selectByUnique(DEFAULT_SELECT_CONFIG);
    }

    @Override
    public String getString(String key, String defaultValue) {
        Preconditions.checkArgument(StringUtils.isNotBlank(key), "key must be not blank");
        String cacheKey = getCacheKey(key);
        if (enableCache()) {
            String value = cacheService.get(cacheKey);
            if (value != null) {
                return value;
            }
        }
        String value = Optional.ofNullable(getConfig(key)).map(SysConfig::getConfigValue).orElse(defaultValue);
        if (value != null && enableCache()) {
            cacheService.setex(cacheKey, value, ConfigConstants.SYS_CONFIG_TIMEOUT);
        }
        return value;
    }

    @Override
    public TableDataInfo<SysConfig> select(SysConfigReq req) {
        Preconditions.checkNotNull(req, "req must be not null");
        int total = 0;
        if (req.isPage()) {
            total = sysConfigMapper.count(req);
            if (total == 0) {
                return TableDataInfo.EMPTY;
            }
        }
        return new TableDataInfo<>(total, sysConfigMapper.select(req));
    }

    @Override
    public int batchDelete(List<Long> configIds) {
        Preconditions.checkArgument(CollectionUtils.isNotEmpty(configIds), "configIds must be not empty");
        if (enableCache()) {
            configIds.stream().map(this::getConfig).filter(Objects::nonNull).forEach(config -> cacheService.del(getCacheKey(config.getConfigKey())));
        }
        return sysConfigMapper.batchDelete(configIds);
    }

    /**
     * 加载参数缓存数据
     */
    private void loadingConfigCache() {
        List<SysConfig> configsList = sysConfigMapper.select(new SysConfigReq());
        for (SysConfig config : configsList) {
            cacheService.setex(getCacheKey(config.getConfigKey()), config.getConfigValue(), ConfigConstants.SYS_CONFIG_TIMEOUT);
        }
    }

    @Override
    public void resetConfigCache() {
        Collection<String> keys = cacheService.keys(CacheEnum.SYS_CONFIG.getCacheKey("*"));
        keys.forEach(key -> cacheService.del(key));
        loadingConfigCache();
    }

    private String getCacheKey(String key) {
        return CacheEnum.SYS_CONFIG.getCacheKey(key);
    }

    private boolean enableCache() {
        return cacheService != null;
    }

}
